package com.hilinos.gb.gb28181.processor.request.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import javax.sip.RequestEvent;
import javax.sip.header.AuthorizationHeader;
import javax.sip.header.ContactHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;

import com.google.common.eventbus.EventBus;
import com.hilinos.gb.gb28181.config.SipConfig;
import com.hilinos.gb.gb28181.processor.SipProcessorFactory;
import com.hilinos.gb.gb28181.processor.event.DeviceOfflineEvent;
import com.hilinos.gb.gb28181.processor.event.DeviceRegisterEvent;
import com.hilinos.gb.gb28181.processor.request.IRequestProcessor;
import com.hilinos.gb.gb28181.repository.IDeviceRepository;
import com.hilinos.gb.gb28181.repository.mysql.mapper.po.Device;
import com.hilinos.gb.gb28181.utils.DigestAuthenticationUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import gov.nist.javax.sip.header.Expires;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component("registerRequestProcessor")
public class RegisterRequestProcessor implements IRequestProcessor {

    @Autowired
    private SipProcessorFactory sipProcessorFactory;

    @Autowired
    private EventBus eventBus;

    @Autowired
    private SipConfig sipConfig;

    @Autowired
    private IDeviceRepository iDeviceRepository;

    @SneakyThrows
    @Override
    public void process(RequestEvent requestEvent) {
        Request request = requestEvent.getRequest();
        Device device = null;
        AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
        boolean passwordCorrect = false;
        // 校验密码是否正确
        if (authorhead != null) {
            passwordCorrect = new DigestAuthenticationUtils().doAuthenticatePlainTextPassword(request,
                    sipConfig.getSipPassword());
        }
        Response response = null;
        int registerFlag = 0;
        // 如果没有认证信息或者认证失败，返回401
        if (sipConfig.isNeedAuth() && (authorhead == null || !passwordCorrect)) {
            if (authorhead == null) {
                log.info("没有授权头，返回401并且等待认证");
            } else {
                log.info("密码错误，返回401并且等待认证");
            }
            response = sipProcessorFactory.getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
            new DigestAuthenticationUtils().generateChallenge(sipProcessorFactory.getHeaderFactory(), response, sipConfig.getSipDomain());
        }
        // 如果密码正确，则直接处理注册成功逻辑
        else {
            response = sipProcessorFactory.getMessageFactory().createResponse(Response.OK, request);
            // 添加date头
            response.addHeader(sipProcessorFactory.getHeaderFactory().createDateHeader(Calendar.getInstance(Locale.ENGLISH)));
            ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
            // 添加Contact头
            response.addHeader(request.getHeader(ContactHeader.NAME));
            // 添加Expires头
            response.addHeader(request.getExpires());

            // 1.获取到通信地址等信息，保存到Redis
            FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
            ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
            String received = viaHeader.getReceived();
            int rPort = viaHeader.getRPort();
            // 解析本地地址替代
            if (ObjectUtils.isEmpty(received)) {
                received = viaHeader.getHost();
                rPort = viaHeader.getPort();
            }
            //
            AddressImpl address = (AddressImpl) fromHeader.getAddress();
            SipUri uri = (SipUri) address.getURI();
            String deviceId = uri.getUser();
            device = new Device();
            device.setDeviceId(deviceId);
            device.setIp(received);
            device.setPort(rPort);
            // 注销成功
            if (expiresHeader != null && expiresHeader.getExpires() == 0) {
                registerFlag = 2;
            }
            // 注册成功
            else {
                registerFlag = 1;
                // 判断TCP还是UDP
                ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
                String transport = reqViaHeader.getTransport();
                device.setTransport(transport.equals("TCP") ? "TCP" : "UDP");
            }
        }

        sipProcessorFactory.getServerTransaction(requestEvent).sendResponse(response);
        // 注册成功
        // 1.保存到数据库或者其他存储
        // 2.返回给结果IP_CAMERA
        if (registerFlag == 1) {
            log.info("注册成功! deviceId:{}", device.getDeviceId());
            device.setRegisterTime(new Date());
            iDeviceRepository.update(device);
            eventBus.post(DeviceRegisterEvent.builder()
                    .device(device)
                    .build());
        } else if (registerFlag == 2) {
            System.out.println("注销成功! deviceId:" + device.getDeviceId());
            eventBus.post(DeviceOfflineEvent.builder().deviceId(device.getDeviceId()).build());
        }
    }

}
